package com.hhd.flow.engine.cmd.impl;

import com.alibaba.fastjson.JSONObject;
import com.hhd.flow.engine.cmd.PassTaskContext;
import com.hhd.flow.engine.support.FlowFormSupportDelegate;
import com.hhd.flow.engine.utils.CommonUtils;
import com.hhd.flow.engine.utils.FlowUtils;
import com.hhd.flow.engine.vo.*;
import com.hhd.flow.entity.*;
import com.hhd.flow.exception.FlowException;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.SuperBuilder;

import java.util.List;

@Setter
@Getter
@SuperBuilder(toBuilder = true)
public class CompleteUserTaskCommand extends FlowUserTaskChangeCommand<Void> {
    private String flowUserTaskId;//待审批的用户任务
    private UserManualSelect userManualSelect; //手动指定的审批人
    private JSONObject formModel; //业务单据的数据
    private String comment; //用户的评论
    private String userSign; //用户的手签
    private String attachmentIds; //附件列表
    private ApproveType approveType;//用户的处理类型
    private String commentInfo; //评论其他信息(用来给前端做特殊展示, json格式)

    //下面是运转过程中产生的数据
    private FlowUserTask flowUserTask;
    private FlowComment flowComment;
    private FlowProcessInstance flowProcessInstance;

    @Override
    public Void execute() {
        loadFlowUserTask();

        createComment();

        publishFlowUserTaskBeforeCompleteEvent();

        doCompleteUserTask();

        publishFlowUserTaskAfterCompleteEvent();

        passTask(createPassTaskContext());

        forFlowUserDone(flowUserTask.getFormId());

        afterChangeFlowUserTask(flowProcessInstance); //触发创建用户任务的事件

        autoComplete(flowProcessInstance, formModel, userManualSelect); //自动审批完成触发
        return null;
    }

    private PassTaskContext createPassTaskContext() {
        return PassTaskContext.builder()
                .variablesContainer(getVariablesContainer(flowUserTask.getFormTypeId(), flowUserTask.getFormId(), flowProcessInstance, getFormModel()))
                .formTypeId(flowUserTask.getFormTypeId())
                .formId(flowUserTask.getFormId())
                .flowTaskId(flowUserTask.getTaskInstanceId())
                .userManualSelect(userManualSelect)
                .formModel(formModel)
                .flowProcessInstanceId(flowUserTask.getProcessInstanceId())
                .build();
    }

    private void publishFlowUserTaskAfterCompleteEvent() {
        publishUserTaskCompleteAfterEveryEvent(this);
    }

    private void doCompleteUserTask() {
        FlowFormSupportDelegate.getInstance().onCompleteUserTask(formModel, flowUserTask.getFormTypeId());
        FlowUserTaskHistory history = createHistory();
        addTaskExecuteCount(history);
    }

    private void createComment() {
        flowComment = FlowUtils.createComment(this.flowUserTask, comment, userSign, attachmentIds, approveType, commentInfo);
        if (CommonUtils.isEmpty(flowComment.getMessage()) && !CommonUtils.isEmpty(approveType)) {
            flowComment.setMessage(approveType.getTitle());
        }
        getEngine().getFlowCommentService().save(flowComment);
    }

    private void addTaskExecuteCount(FlowUserTaskHistory history) {
        FlowTask flowTask = getEngine().getFlowTaskService().getById(history.getTaskInstanceId());
        getEngine().getFlowTaskService().lambdaUpdate()
                .set(FlowTask::getExecuteCount, flowTask.getExecuteCount() + 1)
                .eq(FlowTask::getId, flowTask.getId())
                .update();
        flowTask.setExecuteCount(flowTask.getExecuteCount() + 1);

        if (flowTask.getExecuteCount() < flowTask.getExecuteThreshold()
                && UserTask.ExecuteWay.forName(flowTask.getExecuteWay()) == UserTask.ExecuteWay.multiSequence) {
            String[] userIds = flowTask.getUserIds().split(",");
            String[] userNames = flowTask.getUserNames().split(",");

            FlowProcessInstance flowProcessInstance = getEngine().getFlowProcessInstanceService().getById(flowUserTask.getProcessInstanceId());

            FlowModel flowModel = loadModelByFlowProcessInstanceId(flowProcessInstance.getId());
            UserTask userTask = flowModel.getUserTaskById(flowTask.getTaskDefinitionId());

            FlowUserTask newFlowUserTask = FlowUtils.createFlowUserTask(flowTask, new FlowUser(userIds[flowTask.getExecuteCount()], userNames[flowTask.getExecuteCount()]), flowProcessInstance, userTask);
            getEngine().getFlowUserTaskService().save(newFlowUserTask);
        }
    }

    private FlowModel loadModelByFlowProcessInstanceId(String flowProcessInstanceId) {
        FlowProcessInstance flowProcessInstance = getEngine().getFlowProcessInstanceService().getById(flowProcessInstanceId);
        if (!CommonUtils.isEmpty(flowProcessInstance.getModel())) {
            return getModel(flowProcessInstance);
        }

        List<FlowProcessDefinitionRef> list = getEngine().getFlowProcessDefinitionRefService().lambdaQuery()
                .eq(FlowProcessDefinitionRef::getId, flowProcessInstance.getProcessDefinitionId())
                .list();
        if (list.isEmpty()) throw new FlowException("没有找到流程定义引用");
        return getModel(list.get(0));
    }

    private FlowUserTaskHistory createHistory() {
        FlowUtils.endFlowUserTask(flowUserTask, approveType, userSign);
        FlowUserTaskHistory his = CommonUtils.copyTo(flowUserTask, FlowUserTaskHistory.class);
        getEngine().getFlowUserTaskHistoryService().save(his);
        getEngine().getFlowUserTaskService().removeById(flowUserTaskId);
        return his;
    }


    private void publishFlowUserTaskBeforeCompleteEvent() {
        publishUserTaskCompleteBeforeEveryEvent(this);
        beforeChangeFlowUserTask(flowProcessInstance = getEngine().getFlowProcessInstanceService().getById(flowUserTask.getProcessInstanceId()));
    }

    private void loadFlowUserTask() {
        flowUserTask = getEngine().getFlowUserTaskService().getById(flowUserTaskId);
        CommonUtils.isEmptyThrow(flowUserTask, new FlowException("没有找到用户任务: " + flowUserTaskId + "请刷新页面后重试"));
    }
}
